package utils

import (
	"errors"
	"fmt"
	"github.com/carmel/gooxml/document"
	"log"
	"regexp"
	"strconv"
	"strings"
)

func padZero(num int, size int) string {
	// 将整数转换为字符串
	s := strconv.Itoa(num)
	// 计算需要补零的数量
	padding := size - len(s)
	if padding > 0 {
		// 创建一个由零组成的字符串
		pad := strings.Repeat("0", padding)
		// 将补零的字符串与原始数字字符串拼接
		s = pad + s
	}
	return s
}

func GetParaContext(p document.Paragraph) string {
	ParaText := ""
	for _, r := range p.Runs() {
		runText := r.Text()
		ParaText = ParaText + runText
	}
	return ParaText
}

func SetParaContext(p document.Paragraph, data []string) {
	j := 0
	process := false
	for _, r := range p.Runs() {
		runText := r.Text()
		isStart := strings.Index(runText, "{")
		isEnd := strings.Index(runText, "}")
		endCounter := strings.Count(runText, "}")
		if isStart != -1 && isEnd != -1 {
			r.ClearContent()
			newText := runText[:isStart] + data[j] + runText[isEnd+endCounter:]
			r.AddText(newText)
			j = j + 1
			continue
		}

		if isStart != -1 && isEnd == -1 {
			newText := runText[:isStart]
			r.ClearContent()
			r.AddText(newText)
			process = true
			continue
		}

		if isStart == -1 && isEnd != -1 {
			newText := data[j] + runText[isEnd+endCounter:]
			r.ClearContent()
			r.AddText(newText)
			process = false
			j = j + 1
			continue
		}

		if process {
			r.ClearContent()
		}
	}
}

func GetTagText(text string, starter int) ([]string, []string) {
	tagContainer := make([]string, 0)
	RTextContainer := make([]string, 0)
	ItemList := regexp.MustCompile("\\{\\{.*?}}").FindAllIndex([]byte(text), -1)
	if ItemList == nil {
		return RTextContainer, tagContainer
	}

	for i, _ := range ItemList {
		tag := fmt.Sprintf("D-%v", padZero(starter+i, 3))
		reTag := fmt.Sprintf("{{D-%v}}", padZero(starter+i, 3))
		tagContainer = append(tagContainer, tag)
		RTextContainer = append(RTextContainer, reTag)
	}

	return RTextContainer, tagContainer
}

func FillTagText(text string, data map[string]interface{}) []string {

	RTextContainer := make([]string, 0)
	ItemList := regexp.MustCompile("\\{\\{.*?}}").FindAllIndex([]byte(text), -1)
	if ItemList == nil {
		return RTextContainer
	}

	for _, item := range ItemList {
		key := text[item[0]+2 : item[1]-2]
		value, ok := data[strings.TrimSpace(key)]
		if ok {
			RTextContainer = append(RTextContainer, fmt.Sprintf("%v", value))
		} else {
			RTextContainer = append(RTextContainer, fmt.Sprintf("{{%v}}", key))
		}
	}

	return RTextContainer
}

func WordSDKResolve(wordPath string, saveWordPath string) ([]string, error) {
	tagContainer := make([]string, 0)
	counter := 0
	doc, err := document.Open(wordPath) // 获取模板文档路径
	if err != nil {
		return make([]string, 0), errors.New("not docx")
	}

	// 处理段落信息
	var paragraphs []document.Paragraph
	for _, p := range doc.Paragraphs() {
		paragraphs = append(paragraphs, p)
	}

	//处理表格信息
	for _, tbl := range doc.Tables() {
		for _, row := range tbl.Rows() {
			for _, cell := range row.Cells() {
				for _, p := range cell.Paragraphs() {
					paragraphs = append(paragraphs, p)
				}
			}
		}
	}

	for _, p := range paragraphs {

		pText := GetParaContext(p)
		rText, cn := GetTagText(pText, counter)
		counter = counter + len(cn)
		if len(cn) != 0 {
			tagContainer = append(tagContainer, cn...)
			SetParaContext(p, rText)
		}
	}

	err1 := doc.SaveToFile(saveWordPath)
	if err1 != nil {
		log.Fatalf("error close document: %s", err1)
	}
	return tagContainer, nil
}

func WordSDKFill(wordPath string, saveWordPath string, data map[string]interface{}) error {
	doc, err := document.Open(wordPath) // 获取模板文档路径
	if err != nil {
		return err
	}

	// 处理段落
	var paragraphs []document.Paragraph
	for _, p := range doc.Paragraphs() {
		paragraphs = append(paragraphs, p)
	}

	//处理表格信息
	for _, tbl := range doc.Tables() {
		for _, row := range tbl.Rows() {
			for _, cell := range row.Cells() {
				for _, p := range cell.Paragraphs() {
					paragraphs = append(paragraphs, p)
				}
			}
		}
	}

	for _, p := range paragraphs {
		pText := GetParaContext(p)
		rText := FillTagText(pText, data)
		if len(rText) != 0 {
			SetParaContext(p, rText)
		}

	}

	err1 := doc.SaveToFile(saveWordPath)
	if err1 != nil {
		return err
	}
	return nil
}
